package org.dromara.admin.tenant.service;

import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.stp.parameter.SaLoginParameter;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.diagnosis.DiagnosisUtils;
import com.alipay.api.request.AlipaySystemOauthTokenRequest;
import com.alipay.api.request.AlipayUserInfoShareRequest;
import com.alipay.api.response.AlipaySystemOauthTokenResponse;
import com.alipay.api.response.AlipayUserInfoShareResponse;
import lombok.extern.slf4j.Slf4j;
import org.dromara.admin.constant.HouseGlobalConstant;
import org.dromara.admin.domain.UserDetail;
import org.dromara.admin.domain.bo.UserDetailBo;
import org.dromara.admin.service.IUserDetailService;
import org.dromara.common.core.constant.SystemConstants;
import org.dromara.common.core.constant.TenantConstants;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.core.domain.model.XcxLoginUser;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.MessageUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.system.domain.vo.SysClientVo;
import org.dromara.system.service.ISysClientService;
import org.dromara.system.service.ISysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.Map;

@Slf4j
@Service
public class AlipayLoginService {

    @Value("${alipay.appId}")
    private String appId;

    @Value("${alipay.privateKey}")
    private String privateKey;

    @Value("${alipay.alipayPublicKey}")
    private String alipayPublicKey;

    @Value("${alipay.serverUrl}")
    private String serverUrl;

    @Value("${alipay.format}")
    private String format;

    @Value("${alipay.charset}")
    private String charset;

    @Value("${alipay.signType}")
    private String signType;

    @Autowired
    private IUserDetailService userDetailService;

    @Autowired
    private ISysClientService clientService;


    public Map<String, Object> login(Map<String, String> params) throws AlipayApiException {
        String authCode = params.get("authCode");
        if (StrUtil.isBlank(authCode)) {
            throw new AlipayApiException("授权码不能为空");
        }
        // 1. 创建AlipayClient
        AlipayClient alipayClient = new DefaultAlipayClient(
            serverUrl, appId, privateKey, format, charset, alipayPublicKey, signType
        );
        // 2. 创建AlipaySystemOauthTokenRequest
        AlipaySystemOauthTokenRequest request = new AlipaySystemOauthTokenRequest();
        request.setGrantType("authorization_code"); // 授权方式
        request.setCode(authCode); // 授权码

        // 3. 调用接口
        AlipaySystemOauthTokenResponse response = alipayClient.execute(request);
        if (!response.isSuccess()) {
            log.error(DiagnosisUtils.getDiagnosisUrl(response));
            throw new ServiceException("支付宝授权失败: " + response.getMsg());
        }

        // 4. 获取用户授权信息
        AlipayUserInfoShareRequest userInfoReq = new AlipayUserInfoShareRequest();
        AlipayUserInfoShareResponse userInfoResp = alipayClient.execute(userInfoReq, response.getAccessToken());
        if (!userInfoResp.isSuccess()) {
            throw new RuntimeException("获取用户信息失败: " + userInfoResp.getMsg());
        }
        // 4.1获取用户支付宝信息
        String phone = userInfoResp.getMobile(); // 手机号
        String nickName = userInfoResp.getNickName(); // 昵称
        String isCertified = userInfoResp.getIsCertified(); // 是否实名认证
        String certNo = ""; // 身份证号码
        String realName = ""; // 姓名
        if ("T".equals(isCertified)) {
            certNo = userInfoResp.getCertNo();
            realName = userInfoResp.getUserName();
        }
        // 支付宝唯一用户ID
        String alipayOpenId = response.getOpenId();

        // 查询 userDetail 是否已有该支付宝账号
        UserDetailBo userDetailBo = userDetailService.selectUserByAlipayOpenId
            (realName, nickName, phone, certNo, alipayOpenId);

        // 生成 RuoYi 的登录 Token
        String clientId = params.get("clientId");
        SysClientVo client = clientService.queryByClientId(clientId);
        if (ObjectUtil.isNull(client)) {
            log.info("客户端id: {} 异常!.", clientId);
            throw new ServiceException(MessageUtils.message("auth.grant.type.error"));
        } else if (!SystemConstants.NORMAL.equals(client.getStatus())) {
            throw new ServiceException(MessageUtils.message("auth.grant.type.blocked"));
        }
        XcxLoginUser loginUser = new XcxLoginUser();
        loginUser.setTenantId(TenantConstants.DEFAULT_TENANT_ID);
        loginUser.setUserId(userDetailBo.getUserId());
        loginUser.setUserType(HouseGlobalConstant.APP_USER);
        loginUser.setClientKey(client.getClientKey());
        loginUser.setDeviceType(client.getDeviceType());
        loginUser.setOpenid(alipayOpenId);

        SaLoginParameter model = new SaLoginParameter();
        model.setDeviceType(client.getDeviceType());
        // 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置
        // 例如: 后台用户30分钟过期 app用户1天过期
        model.setTimeout(client.getTimeout());
        model.setActiveTimeout(client.getActiveTimeout());
        model.setExtra(LoginHelper.CLIENT_KEY, client.getClientId());
        LoginHelper.login(loginUser, model);

        return Map.of("userDetail", userDetailBo,
            "data", response.getBody(),
            "accessToken", StpUtil.getTokenValue(),
            "expireIn", StpUtil.getTokenTimeout(),
            "clientId", client.getClientId(),
            "openid", alipayOpenId);
    }
}
